package com.lcy.accumulation.export.excel;


import com.lcy.accumulation.export.setting.*;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;

import java.io.IOException;
import java.io.OutputStream;
import java.util.*;

/**
 * 只支持 xls 导出
 * <p>创建时间：2017-5-23 13:47</p>
 *
 * @author 娄存银
 * @version 1.0
 */
public class ExcelExportHelper extends ExportHelper {
    private Workbook workbook;
    private Sheet sheet;
    private Short rowHeight;

    public ExcelExportHelper(TableSetting setting, Map<String, Object> header) {
        super(setting, header);
    }

    public ExcelExportHelper(TableSetting setting, List<Map<String, Object>> body) {
        super(setting, body);
    }

    public ExcelExportHelper(TableSetting setting, Map<String, Object> header, List<Map<String, Object>> body) {
        super(setting, header, body);
    }

    @Override
    public void export(OutputStream outputStream) throws IOException {
        if (!isValid() || outputStream == null) {
            return;
        }

        init();
        
        if(workbook != null){
            try {
                workbook.write(outputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                outputStream.flush();
                outputStream.close();
            }
        }
    }

    public Workbook getWorkbook() {
        if (workbook == null) {
            workbook = initWorkbookFromSetting(getTemplateSetting());
        }
        return workbook;
    }

    private Sheet getSheet() {
        if (sheet != null) {
            return sheet;
        }

        ExportTemplate template = getTemplateSetting();
        int index = 0;
        if (template != null) {
            index = template.getIndex();
        }

        sheet = getSheet(getWorkbook(), index);
        return sheet;
    }

    @Override
    protected void afterExport() {
        AfterExportHandler handler = setting.getHandler();
        if(handler != null) {
            handler.handler(sheet);
        }
    }

    @Override
    protected void writeHeader() {
        if (header == null) {
            return;
        }
        List<ExportCell> cells = getHeaderCells();
        if(cells == null || cells.size() == 0){
            return;
        }
        
        for (ExportCell exportCell : cells) {
            Cell cell = getCell(getSheet(), exportCell.getRow(), exportCell.getColumn());
            Object object = header.get(exportCell.getKey());
            writeDateToCell(cell, object,null);
        }
    }

    @Override
    protected void writeBody() {
        if (!isValidBody()) {
            return;
        }
        ExportBody bodySetting = getBodySetting();
        if (bodySetting == null) {
            return;
        }

        Sheet sheet = getSheet();
        int rowNumber = bodySetting.getRow();

        for (Map<String, Object> map : body) {
            Row row = getRow(sheet, rowNumber);
            writeBodyToRow(row, map);
            rowNumber++;
        }
    }

    private void writeBodyToRow(Row row, Map<String, Object> map) {
        List<ExportColumn> columns = getColumns();
        if (columns == null || row == null || map == null) {
            return;
        }

        if(rowHeight == null){
            rowHeight = row.getHeight();
        }else {
            row.setHeight(rowHeight);
        }

        // 创建日期格式
        Workbook workbook = row.getSheet().getWorkbook();
        ExportStyle exportStyle = getStyleSetting();
        CellStyle sheetStyle = workbook.createCellStyle();
        initCellStyle(sheetStyle);
        if (exportStyle != null && exportStyle.getDateFormat() != null) {
            short dateFormat = workbook.createDataFormat().getFormat(exportStyle.getDateFormat());
            sheetStyle.setDataFormat(dateFormat);
        }
        ColumnHandler handler = getColumnHandler();
        Map<String,CellStyle> styleMap =new HashMap<>();
        for (ExportColumn column : columns) {
            String format = column.getDateFormat();
            if(format != null){
                CellStyle style = workbook.createCellStyle();
                initCellStyle(style);
                short dateFormat = workbook.createDataFormat().getFormat(format);
                style.setDataFormat(dateFormat);
                styleMap.put(column.getKey(),style);
            }
        }

        for (ExportColumn column : columns) {
            Integer index = column.getColumn();
            String dateFormat = column.getDateFormat();
            if (index != null) {
                Cell cell = row.getCell(column.getColumn());
                if (cell == null) {
                    cell = row.createCell(column.getColumn());
                }
                Object object = map.get(column.getKey());
                if(handler != null){
                    object = handler.handle(column.getKey(),map);
                }
                CellStyle style = styleMap.get(column.getKey());
                if(style == null){
                    style = sheetStyle;
                }
                writeDateToCell(cell, object,style);
            }
        }
    }

    private void writeDateToCell(Cell cell, Object object, CellStyle style) {
        if (cell == null) {
            return;
        }
        if(style != null){
            cell.setCellStyle(style);
        }
        if(object == null){
            return;
        }
        if (object instanceof Date) {
            cell.setCellValue((Date) object);
        } else if (object instanceof Calendar) {
            cell.setCellValue((Calendar) object);
        } else if (object instanceof RichTextString) {
            cell.setCellValue((RichTextString) object);
        } else {
            cell.setCellValue(object.toString());
        }
    }

    /**
     * 从 excel 初始化一个 workBook，读取 excel 中的模板信息，如果存在模板，打开模板，不存在则新建一个
     *
     * @param template 模板信息
     * @return workbook
     */
    private Workbook initWorkbookFromSetting(ExportTemplate template) {
        Workbook workbook = null;
        if (template != null && template.hasTemplate()) {
            try {
                workbook = WorkbookFactory.create(template.getTemplate());
            } catch (Exception ignored) {
            }
        }

        if (workbook == null) {
            workbook = new HSSFWorkbook();
        }

        return workbook;
    }

    /**
     * 从 workbook 根据 index 初始化 sheet ,有则获取，没有就新建
     *
     * @param workbook workbook
     * @param index    sheet 所在的位置
     * @return sheet
     */
    private Sheet getSheet(Workbook workbook, int index) {
        if (workbook == null) {
            return null;
        }
        Sheet sheet = null;
        if (workbook.getNumberOfSheets() > index) {
            sheet = workbook.getSheetAt(index);
        }
        if (sheet == null) {
            sheet = workbook.createSheet();
        }
        return sheet;
    }

    /**
     * 从 sheet 根据 row 所在位置 初始化 row ,有则获取，没有就新建
     *
     * @param sheet     sheet
     * @param rowNumber 行号
     * @return row
     */
    private Row getRow(Sheet sheet, int rowNumber) {
        if (sheet == null) {
            return null;
        }
        Row row = sheet.getRow(rowNumber);
        if (row == null) {
            row = sheet.createRow(rowNumber);
        }
        return row;
    }

    /**
     * 从 row 根据 column 初始化 cell ,有则获取，没有就新建
     *
     * @param row          row
     * @param columnNumber 第几列
     * @return cell
     */
    private Cell getCell(Row row, int columnNumber) {
        if (row == null) {
            return null;
        }
        Cell cell = row.getCell(columnNumber);
        if (cell == null) {
            cell = row.createCell(columnNumber);
        }
        return cell;
    }

    private Cell getCell(Sheet sheet, int rowNumber, int columnNumber) {
        if (sheet == null) {
            return null;
        }
        Row row = getRow(sheet, rowNumber);
        return getCell(row, columnNumber);
    }

    private void initCellStyle(CellStyle style){
        if(style == null){
            return;
        }
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderTop(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setAlignment(HorizontalAlignment.CENTER);
    }
}
